package com.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.annotation.IgnoreAuth;
import com.dao.MeishiCollectionDao;
import com.dao.MeishiDao;
import com.dao.MeishiRatingDao;
import com.entity.MeishiCollectionEntity;
import com.entity.MeishiEntity;
import com.entity.view.MeishiCollectionView;
import com.entity.view.MeishiView;
import com.model.enums.ItemType;
import com.service.MeishiService;
import com.service.RecommendationService;
import com.service.DeepSeekService;
import com.utils.CommonUtil;
import com.utils.PageUtils;
import com.utils.R;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.mapper.EntityWrapper;

/**
 * 健康食谱推荐 服务实现类
 */
@Service("recommendationService")
public class RecommendationServiceImpl extends ServiceImpl<MeishiCollectionDao, MeishiCollectionEntity> implements RecommendationService {

    @Autowired
    private MeishiCollectionDao meishiCollectionDao;

    @Autowired
    private MeishiRatingDao meishiRatingDao;

    @Autowired
    private MeishiService meishiService;

    @Autowired
    private MeishiDao meishiDao;

    @Autowired
    private DeepSeekService deepSeekService;

    // 如有评分表
    // @Autowired

    /**
     *  1. 推荐ID列表
     * 基于用户协同过滤的美食推荐
     * @param userId 当前用户ID
     * @param limit 推荐数量
     * @return 推荐的美食ID列表
     */
    public List<String> getUserBasedRecommendations(String userId, int limit) {
        // 1. 获取当前用户收藏的美食
        Set<String> myMeishiSet = new HashSet<>(meishiCollectionDao.findMeishiIdsByUserId(userId));

        // 2. 获取所有用户的收藏关系
        List<Map<String, Object>> allRelations = meishiCollectionDao.findAllUserMeishiRelations();

        // 3. 构建用户-美食倒排表
        Map<String, Set<String>> userMeishiMap = new HashMap<>();
        for (Map<String, Object> rel : allRelations) {
            String uid = String.valueOf(rel.get("yonghu_id"));
            String mid = String.valueOf(rel.get("meishi_id"));
            userMeishiMap.computeIfAbsent(uid, k -> new HashSet<>()).add(mid);
        }

        // 4. 计算与其他用户的Jaccard相似度
        Map<String, Double> similarityMap = new HashMap<>();
        for (Map.Entry<String, Set<String>> entry : userMeishiMap.entrySet()) {
            String otherUserId = entry.getKey();
            if (otherUserId.equals(userId)) continue;
            Set<String> otherSet = entry.getValue();
            double sim = calculateJaccard(myMeishiSet, otherSet);
            similarityMap.put(otherUserId, sim);
        }

        // 5. 选取Top-K相似用户
        List<String> similarUsers = similarityMap.entrySet().stream()
                .filter(e -> e.getValue() > 0.1) // 阈值可调
                .sorted(Map.Entry.<String, Double>comparingByValue().reversed())
                .limit(10)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

        // 6. 推荐这些用户喜欢但当前用户未收藏的美食
        Map<String, Double> itemScores = new HashMap<>();
        for (String simUser : similarUsers) {
            double sim = similarityMap.get(simUser);
            Set<String> simUserMeishi = userMeishiMap.get(simUser);
            if (simUserMeishi != null) {
                for (String mid : simUserMeishi) {
                    if (!myMeishiSet.contains(mid)) {
                        itemScores.merge(mid, sim, Double::sum);
                    }
                }
            }
        }

        System.out.println("itemScores.size()" + itemScores.size());
        System.out.println("limit" + limit);
        // 7. 推荐列表不足时，自动补充“收藏数量最多的美食”
        if (itemScores.size() < limit) {
            // 查询所有美食的收藏数量，按降序排列
            List<MeishiEntity> hotList = getHotMeishiByCollection();
            System.out.println("hotList: " + JSONObject.toJSONString(hotList));
            // 已经推荐过的和已收藏的都不能再推荐
            Set<String> already = new HashSet<>(itemScores.keySet());
            already.addAll(myMeishiSet);

            for (MeishiEntity entity : hotList) {
                String mid = String.valueOf(entity.getId());
                if (!already.contains(mid)) {
                    itemScores.put(mid, 0.0); // 补充的美食，分数设为0或任意
                    if (itemScores.size() >= limit) break;
                }
            }
        }

        // 8. 返回前limit个推荐
        return itemScores.entrySet().stream()
                .sorted(Map.Entry.<String, Double>comparingByValue().reversed())
                .limit(limit)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }

    /**
     * 获取基于用户的推荐美食视图列表
     */
    public List<MeishiView> getUserBasedRecommendationViews(String userId, int page, int limit) {
        // 1. 获取推荐ID列表
        List<String> recommendIds = getUserBasedRecommendations(userId, page * limit);

        // 2. 查询所有详情
        List<MeishiEntity> entityList = meishiService.selectBatchIds(recommendIds);
        List<MeishiView> recommendList = entityList.stream()
                .map(entity -> {
                    MeishiView view = new MeishiView();
                    BeanUtils.copyProperties(entity, view);
                    return view;
                })
                .collect(Collectors.toList());

        // 3. 用Map加速查找
        Map<String, MeishiView> id2View = recommendList.stream()
                .collect(Collectors.toMap(v -> String.valueOf(v.getId()), v -> v));

        // 4. 按推荐ID顺序重新组装，并做分页切片
        int from = Math.max(0, (page - 1) * limit);
        int to = Math.min(recommendIds.size(), from + limit);
        List<String> pageIds = recommendIds.subList(from, to);

        List<MeishiView> sortedList = pageIds.stream()
                .map(id2View::get)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        // 5. 返回排序后的列表
        return sortedList;
    }

    /**
     * 获取用户相似度矩阵
     * 计算所有用户之间的相似度
     *
     * @param itemType 物品类型
     * @return 用户相似度矩阵
     */
    @Override
    public Map<String, Map<String, Double>> getUserSimilarityMatrix(ItemType itemType) {
        // 1. 查询所有用户-美食收藏关系
        List<Map<String, Object>> allRelations = meishiCollectionDao.findAllUserMeishiRelations();

        // 2. 构建用户-美食集合
        Map<String, Set<String>> userItemMap = new HashMap<>();
        for (Map<String, Object> rel : allRelations) {
            String userId = String.valueOf(rel.get("yonghu_id"));
            String itemId = String.valueOf(rel.get("meishi_id"));
            userItemMap.computeIfAbsent(userId, k -> new HashSet<>()).add(itemId);
        }

        // 3. 计算用户两两之间的Jaccard相似度
        Map<String, Map<String, Double>> similarityMatrix = new HashMap<>();
        List<String> users = new ArrayList<>(userItemMap.keySet());
        for (int i = 0; i < users.size(); i++) {
            String user1 = users.get(i);
            for (int j = i + 1; j < users.size(); j++) {
                String user2 = users.get(j);
                double sim = calculateJaccard(userItemMap.get(user1), userItemMap.get(user2));
                similarityMatrix.computeIfAbsent(user1, k -> new HashMap<>()).put(user2, sim);
                similarityMatrix.computeIfAbsent(user2, k -> new HashMap<>()).put(user1, sim);
            }
        }
        return similarityMatrix;
    }

    /**
     * 计算Jaccard相似度
     */
    private double calculateJaccard(Set<String> set1, Set<String> set2) {
        if (set1 == null || set2 == null || (set1.isEmpty() && set2.isEmpty())) return 0.0;
        Set<String> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        Set<String> union = new HashSet<>(set1);
        union.addAll(set2);
        if (union.isEmpty()) return 0.0;
        return (double) intersection.size() / union.size();
    }

    /**
     * 收藏数量降序排列的美食列表（补充推荐）
     * @return 热门美食列表（全部，按收藏的数量降序）
     */
    public List<MeishiEntity> getHotMeishiByCollection() {
        // 1. 查询所有美食的收藏数量
        List<Map<String, Object>> collectionCounts = meishiCollectionDao.selectMeishiCollectionCounts();

        // 2. 获取排序后的美食ID列表
        List<String> meishiIds = collectionCounts.stream()
                .map(map -> String.valueOf(map.get("meishi_id")))
                .collect(Collectors.toList());

        // 3. 查询美食详情
        List<MeishiEntity> hotMeishiList = meishiDao.selectBatchIds(meishiIds);

        // 4. 按收藏数量顺序重新排序
        Map<String, MeishiEntity> id2Meishi = hotMeishiList.stream()
                .collect(Collectors.toMap(
                        meishi -> String.valueOf(meishi.getId()),
                        meishi -> meishi
                ));

        // 5. 返回按收藏数量降序排列的美食列表
        List<MeishiEntity> sortedList = meishiIds.stream()
                .map(id2Meishi::get)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        System.out.println("sortedList" + sortedList);
        System.out.println("sortedList: " + sortedList.stream().map(MeishiEntity::getId).collect(Collectors.toList()));
        return sortedList;
    }

    /**
     * 热门美食（按收藏数降序）的视图分页
     */
    public List<MeishiView> getHotMeishiByCollectionViews(int page, int limit) {
        List<MeishiEntity> hotAll = getHotMeishiByCollection();
        if(hotAll == null || hotAll.isEmpty()) return Collections.emptyList();

        int from = Math.max(0, (page - 1) * limit);
        int to = Math.min(hotAll.size(), from + limit);
        List<MeishiEntity> pageEntities = hotAll.subList(from, to);

        return pageEntities.stream().map(entity -> {
            MeishiView view = new MeishiView();
            BeanUtils.copyProperties(entity, view);
            return view;
        }).collect(Collectors.toList());
    }

    /**
     * 收藏数量降序排列的美食列表（补充推荐）
     * @return 热门美食列表（全部，按收藏的数量降序）
     */
    public List<MeishiEntity> getHotMeishiByZan() {
        return null;
    }
    
    /**
     * 获取AI增强的个性化推荐
     * @param userId 用户ID
     * @param limit 推荐数量
     * @return 包含AI建议的推荐结果
     */
    public Map<String, Object> getAIEnhancedRecommendations(String userId, int limit) {
        Map<String, Object> result = new HashMap<>();
        
        // 1. 获取传统推荐结果
        List<MeishiView> recommendations = getUserBasedRecommendationViews(userId, 1, limit);
        result.put("recommendations", recommendations);
        
        // 2. 获取用户收藏的美食信息，用于AI分析
        List<String> userMeishiIds = meishiCollectionDao.findMeishiIdsByUserId(userId);
        List<MeishiEntity> userMeishiList = meishiService.selectBatchIds(userMeishiIds);
        
        // 3. 构建用户偏好描述
        StringBuilder userPreference = new StringBuilder();
        userPreference.append("用户收藏的美食类型包括：");
        for (MeishiEntity meishi : userMeishiList) {
            userPreference.append(meishi.getMeishiName()).append("、");
        }
        
        // 4. 获取AI个性化建议
        try {
            String systemPrompt = "你是一个专业的营养师和美食推荐专家，请根据用户的饮食偏好，提供个性化的健康饮食建议。";
            String userMessage = String.format("用户偏好：%s，请基于这些偏好提供健康饮食建议和注意事项。", 
                    userPreference.toString());
            
            String aiAdvice = deepSeekService.getChatResponse(userMessage, systemPrompt);
            result.put("aiAdvice", aiAdvice);
        } catch (Exception e) {
            result.put("aiAdvice", "AI建议暂时不可用，请稍后再试。");
        }
        
        return result;
    }


    /**
     * 获取美食列表
     * @param userId
     * @param limit
     * @return
     */
    private List<String> getMeishiList(String userId,int limit){
        // 查询数据库所有有效美食记录（meishi_delete = 1），按时间倒序/ID倒序
        com.baomidou.mybatisplus.mapper.Wrapper<MeishiEntity> wrapper = new EntityWrapper<MeishiEntity>()
                .eq("meishi_delete", 1);

        List<MeishiEntity> all = meishiService.selectList(wrapper);
        if(all == null || all.isEmpty()){
            return Collections.emptyList();
        }

        // 截取 limit 条，返回 ID 字符串列表
        return all.stream()
                .limit(Math.max(0, limit))
                .map(e -> String.valueOf(e.getId()))
                .collect(Collectors.toList());
    }

    /**
     * 获取推荐美食视图列表
     */
    @Override
    public List<MeishiView> getListViews(String userId, int page, int limit) {
        // 1. 获取推荐ID列表（全量），然后在内存分页
        List<String> recommendIds = getMeishiList(userId, Integer.MAX_VALUE);
        System.out.println("List<String> recommendIds = getMeishiList(userId, limit);" + recommendIds);

        // 2. 查询所有详情
        List<MeishiEntity> entityList = meishiService.selectBatchIds(recommendIds);
        List<MeishiView> recommendList = entityList.stream()
                .map(entity -> {
                    MeishiView view = new MeishiView();
                    BeanUtils.copyProperties(entity, view);
                    return view;
                })
                .collect(Collectors.toList());

        // 3. 用Map加速查找
        Map<String, MeishiView> id2View = recommendList.stream()
                .collect(Collectors.toMap(v -> String.valueOf(v.getId()), v -> v));

        // 4. 按推荐ID顺序重新组装 + 分页切片
        int from = Math.max(0, (page - 1) * limit);
        int to = Math.min(recommendIds.size(), from + limit);
        List<String> pageIds = recommendIds.subList(from, to);
        List<MeishiView> sortedList = pageIds.stream()
                .map(id2View::get)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        // 5. 返回排序后的列表
        return sortedList;
    }
}